home *** CD-ROM | disk | FTP | other *** search
- // Thinker.m
- //
- // This class is the brains behind the BackSpace app; it is the Application
- // object's delegate, and it watches the system to determine when to
- // initiate the screen saver mode.
- //
- // You may freely copy, distribute, and reuse the code in this example.
- // NeXT disclaims any warranty of any kind, expressed or implied, as to its
- // fitness for any particular use.
-
-
- #import "Thinker.h"
- #import "BackWindow.h"
- #import "BackView.h"
- #import "SpaceView.h"
- #import "MySlider.h"
- #import "Password.h"
- #import "psfuncts.h"
-
- #import <appkit/appkit.h>
- #import <objc/NXBundle.h>
-
- // convert vertical blank time to milliseconds
- #define SEC2MS(x) ((x * 1000) + 20)
-
- //#define SHOWITERATIONSPERSEC
-
- #ifdef SHOWITERATIONSPERSEC
- unsigned iterations;
- BStimeval then, now, targetTime;
- #endif
-
- static id _BSThinker;
-
- id BSThinker()
- { return _BSThinker;
- }
-
-
- @implementation Thinker
-
- - appDidInit:sender
- {
- const char *autoLaunch;
- globalTier = BACKGROUNDTIER;
- openAnother = YES;
- _BSThinker = self;
-
- backZone = NXCreateZone(vm_page_size, vm_page_size, YES);
-
- NXSetRect(&windowRect, 475, 300, 500, 450);
-
- [NXApp getScreens:&screens count:&screenCount];
-
- [commonImageInspector getFrame: &inspectorFrame];
- currentInspector = commonImageInspector;
-
- [self getViewType];
- [self setVirtualViewIndexAndIncrement:NO];
- [self getWindowType];
-
- [self getScreenSaverSetting];
- [self getScreenLockerSetting];
- [self getPrioritySetting];
- [self getImageFile];
- [self getHotCornerSetting];
-
- autoLaunch = NXGetDefaultValue([NXApp appName], "NXAutoLaunch");
- if (strcmp(autoLaunch,"YES"))
- {
- [[windMatrix window] makeKeyAndOrderFront:self];
- windowHasBeenDisplayed = YES;
- }
- else [NXApp hide:self];
-
- #ifdef SHOWITERATIONSPERSEC
- then = currentTimeInMs();
- targetTime = then + 10000;
- #endif
-
- srandom(time(0));
-
- return self;
- }
-
- - appDidHide:sender
- {
- if (windowType != BACKWINDOW) [self removeTimer];
- return self;
- }
-
- - appDidUnhide:sender
- {
- if (!windowHasBeenDisplayed)
- {
- [[windMatrix window] makeKeyAndOrderFront:self];
- windowHasBeenDisplayed = YES;
- }
-
- if (windowType != NOWINDOW) [self createTimer];
- return self;
- }
-
-
-
- // Pretty much a dummy function to invoke the step method.
-
- void timedEntryFunction (DPSTimedEntry timedEntry, double timeNow, void *theObject)
- { [(id)theObject doDistributorLoop];
- }
-
- - createTimer
- {
- if (!timerValid)
- {
- timerValid = YES;
- timer = DPSAddTimedEntry(0.02, &timedEntryFunction, self, NX_BASETHRESHOLD);
- }
- return self;
- }
-
- - removeTimer
- {
- if (timerValid) DPSRemoveTimedEntry (timer);
- timerValid = NO;
- return self;
- }
-
- - doDistributorLoop
- {
- NXEvent dummyEvent;
-
- keepLooping = YES;
- [spaceView lockFocus];
- if ([spaceView respondsTo:@selector(didLockFocus)]) [spaceView didLockFocus];
-
- do {
- [spaceView oneStep];
- [spaceWindow flushWindow];
- NXPing (); // Synchronize postscript for smoother animation
-
- [spaceView oneStep];
- [spaceWindow flushWindow];
- NXPing (); // Synchronize postscript for smoother animation
-
- #ifdef SHOWITERATIONSPERSEC
- iterations++;
- if ((now = currentTimeInMs()) > targetTime)
- {
- printf("BackSpace: %5.1f its/sec\n",
- (double)iterations*1000.0/(double)(now - then));
- iterations = 0;
- targetTime = now + 10000;
- then = now;
- }
- #endif
-
- } while (timerValid && keepLooping &&
- ([NXApp peekNextEvent:NX_ALLEVENTS into:&dummyEvent
- waitFor:0 threshold:NX_BASETHRESHOLD] == NULL));
-
- [spaceView unlockFocus];
-
- return self;
-
- }
-
- - installSpaceViewIntoWindow:w
- {
- NXRect cvrect;
- int i;
- id subviews, contentView;
-
- if (!w) return nil;
- contentView = [w contentView];
-
- // get size of content view
- [contentView getBounds:&cvrect];
-
- // remove old subviews, this is overkill really...
- subviews = [contentView subviews];
- for (i=([subviews count]-1); i>=0; i--)
- { [[subviews objectAt:i] removeFromSuperview];
- }
-
- // install it into the window's content view
- [contentView addSubview:spaceView];
- [contentView setAutoresizeSubviews:YES];
- [spaceView setAutosizing:NX_WIDTHSIZABLE | NX_HEIGHTSIZABLE];
-
- // size the spaceview
- [spaceView sizeTo:cvrect.size.width :cvrect.size.height];
-
- return self;
- }
-
- - useNormalWindow
- {
- int myBacking;
-
- spaceView = [self backView];
- myBacking = [self backingTypeForView:spaceView];
-
- if (!normalWindow)
- {
- normalWindow = [[Window allocFromZone:backZone]
- initContent:&windowRect style:NX_RESIZEBARSTYLE
- backing:myBacking
- buttonMask:NX_CLOSEBUTTONMASK
- defer:NO];
-
- [self setWindowTitle];
- [normalWindow useOptimizedDrawing:YES];
- [normalWindow setDynamicDepthLimit:YES]; //want window depth to match device!
- [normalWindow setOneShot:YES];
- [normalWindow setDelegate:self];
- [normalWindow setBackgroundGray:NX_BLACK];
- }
-
- spaceWindow = normalWindow;
- [self installSpaceViewIntoWindow:spaceWindow];
-
- if ([spaceView respondsTo:@selector(setImage:)])
- [spaceView setImage: image];
- if ([spaceView respondsTo:@selector(newWindow)]) [spaceView newWindow];
- [spaceWindow display];
-
- [spaceWindow makeKeyAndOrderFront:self];
-
- // need to do this so flushing always works!
- // must do it late because kit does lazy window creation ie the PostScript
- // window might not exist until you actually draw to it
-
- if (myBacking == NX_RETAINED)
- [spaceWindow setBackingType:NX_RETAINED];
- else [spaceWindow setBackingType:NX_BUFFERED];
-
- return self;
- }
-
- - (int) backingTypeForView:aView
- {
- if ([aView respondsTo:@selector(useBufferedWindow)]
- && [aView useBufferedWindow])
- return NX_BUFFERED;
- return NX_RETAINED;
- }
-
- - useBackWindow:(int)tier
- {
- NXRect r={{0, 0}};
- int myBacking;
-
- [NXApp getScreenSize:&(r.size)];
-
- spaceView = [self backView];
- myBacking = [self backingTypeForView:spaceView];
-
- [self createBigWindowIfNecessaryForView:spaceView];
-
- if (myBacking == NX_RETAINED)
- { spaceWindow = bigUnbufferedWindow;
- tweakWindow([spaceWindow windowNum], tier);
- }
- else
- { spaceWindow = bigBufferedWindow;
- }
-
- [self installSpaceViewIntoWindow:spaceWindow];
-
- if ([spaceView respondsTo:@selector(setImage:)])
- [spaceView setImage: image];
-
- [spaceWindow placeWindow:&r];
- if (myBacking == NX_BUFFERED) [spaceWindow display];
-
- [spaceWindow orderFront:self];
- if (myBacking == NX_BUFFERED) tweakWindow([spaceWindow windowNum], tier);
- else [spaceWindow display];
-
- if ([spaceView respondsTo:@selector(newWindow)]) [spaceView newWindow];
-
- return self;
- }
-
- - createBigWindowIfNecessaryForView:aView
- {
- NXRect r={{0, 0}};
- int myBacking = [self backingTypeForView:aView];
-
- [NXApp getScreenSize:&(r.size)];
-
- if ((myBacking == NX_RETAINED) && !bigUnbufferedWindow)
- {
-
- bigUnbufferedWindow = [[BackWindow allocFromZone:backZone]
- initContent:&r style:NX_TOKENSTYLE
- backing:NX_NONRETAINED buttonMask:0 defer:NO];
-
- [bigUnbufferedWindow useOptimizedDrawing:YES];
-
- [bigUnbufferedWindow removeFromEventMask:(NX_LMOUSEDOWNMASK | NX_LMOUSEUPMASK
- | NX_MOUSEMOVEDMASK | NX_LMOUSEDRAGGEDMASK
- | NX_MOUSEENTEREDMASK | NX_MOUSEEXITEDMASK
- | NX_KEYDOWNMASK | NX_KEYUPMASK
- | NX_CURSORUPDATEMASK)];
- [bigUnbufferedWindow setBackgroundGray:NX_BLACK];
- }
-
- if ((myBacking == NX_BUFFERED) && !bigBufferedWindow)
- {
-
- bigBufferedWindow = [[BackWindow allocFromZone:backZone]
- initContent:&r style:NX_TOKENSTYLE
- backing:NX_BUFFERED buttonMask:0 defer:NO];
-
- [bigBufferedWindow useOptimizedDrawing:YES];
-
- [bigBufferedWindow removeFromEventMask:(NX_LMOUSEDOWNMASK | NX_LMOUSEUPMASK
- | NX_MOUSEMOVEDMASK | NX_LMOUSEDRAGGEDMASK
- | NX_MOUSEENTEREDMASK | NX_MOUSEEXITEDMASK
- | NX_KEYDOWNMASK | NX_KEYUPMASK
- | NX_CURSORUPDATEMASK)];
-
- [bigBufferedWindow setDynamicDepthLimit:YES]; //want window depth to match device!
- [bigBufferedWindow setOneShot:YES];
- [bigBufferedWindow setBackgroundGray:NX_BLACK];
- }
-
- return self;
- }
-
- - changeWindowType:sender
- {
- [self changeWindowTypeAndRemember:YES];
- return self;
- }
-
- - changeWindowTypeAndRemember:(BOOL)rem
- {
- char str[10];
- int newWindowType;
-
- newWindowType = [windMatrix selectedRow];
- if (newWindowType == windowType) return self;
-
- windowType = newWindowType;
-
- if (rem)
- {
- sprintf(str,"%1d", windowType);
- NXWriteDefault([NXApp appName], "windowType", str);
- }
-
- [spaceWindow orderOut:self];
-
- switch (windowType)
- {
- case NOWINDOW:
- [self removeTimer];
- break;
- case NORMALWINDOW:
- [self useNormalWindow];
- [self createTimer];
- break;
- case BACKWINDOW:
- [self useBackWindow: globalTier];
- [self createTimer];
- break;
- }
-
- return self;
- }
-
- - getWindowType
- {
- int tWindowType = NORMALWINDOW;
- const char *ptr;
- int val;
-
- ptr = NXGetDefaultValue([NXApp appName], "windowType");
- if (ptr)
- {
- sscanf(ptr,"%d",&val);
- if (val >= 0 && val <= 2) tWindowType = val;
- }
-
- [windMatrix selectCellAt:tWindowType :0];
- [self changeWindowTypeAndRemember:NO];
-
- return self;
- }
-
- - getScreenSaverSetting
- {
- const char *ptr;
-
- if((evs = NXOpenEventStatus()) == 0)
- { perror("NXOpenEventStatus failed.");
- exit(10);
- }
-
- [self getDimBrightness:&dimBrightness];
-
- //in case the old dim brightness is somehow invalid, I reset it
- if (dimBrightness > .25)
- {
- dimBrightness = .25;
- [self _setDimBrightness:&dimBrightness];
- }
-
- [screenSaver setState:0];
-
- ptr = NXGetDefaultValue([NXApp appName], "screenSaver");
-
- if (!ptr || !strcmp(ptr,"Off")) [self setScreenSaver:NO andRemember:NO];
- else [self setScreenSaver:YES andRemember:NO];
-
- return self;
- }
-
- - changeScreenSaverSetting:sender
- {
- [self setScreenSaver:([screenSaver state])andRemember:YES];
- return self;
- }
-
- - setScreenSaver:(BOOL)val andRemember:(BOOL)rem
- {
- [screenSaver setState:val];
- screenSaverVal = val;
-
- if (val)
- {
- // turn it on...
- [self calcDimTime];
- if (rem) NXWriteDefault([NXApp appName], "screenSaver", "On");
- }
- else
- {
- // turn it off...
- if (rem) NXRemoveDefault([NXApp appName], "screenSaver");
- }
-
- return self;
- }
-
- - calcDimTime
- {
- double dimTime;
- [self getDimTime :&dimTime];
-
- if (dimTime < 0) dimTime = .1;
-
- if (screenSaverVal && !doingSaver)
- {
- // printf("BackSpace calcDimTime: dims in %f seconds\n",dimTime);
-
- [self perform:@selector(maybeDoScreenSaver:)
- with:self
- afterDelay:SEC2MS(dimTime)
- cancelPrevious:YES];
- }
-
- return self;
- }
-
- - maybeDoScreenSaver:sender
- {
- NXEvent anEvent;
- BOOL autoDimmed;
-
- // in case timed entry fires but user has killed screen saver
- if (!screenSaverVal || doingSaver) return self;
-
- autoDimmed = NXAutoDimState(evs);
- if (!autoDimmed)
- {
- [self calcDimTime];
- return self;
- }
-
- // The perform:afterDelay: method starts a timed entry to
- // invoke maybeDoScreenSaver, so we are in a timed entry
- // right now. If we just jumped into doScreenSaver:, we
- // would interrupt the doDistributorLoop method while
- // it's still focused on the spaceView. By posting an
- // event, we force that loop to bail out so we can jump
- // into the screen saver cleanly.
-
- keepLooping = NO; // There was a bug related to this at one point.
- // I don't think it's necessary anymore.
- anEvent.type = NX_APPDEFINED;
- anEvent.data.compound.subtype = BSDOSAVER;
- anEvent.ctxt = [NXApp context];
- DPSPostEvent(&anEvent,0);
-
- return self;
- }
-
- - applicationDefined:(NXEvent *)theEvent
- {
- switch (theEvent->data.compound.subtype)
- {
- case BSDOSAVER:
- [self doScreenSaver:self];
- [self calcDimTime]; // reset to fire again
- break;
- case BSOPENFILE:
- [self doDelayedOpenFile];
- break;
- default:
- break;
- }
- return self;
- }
-
- - showFakeScreenSaverAfterPause:sender
- {
- usleep(250000);
- return [self showFakeScreenSaver:sender];
- }
-
- - showFakeScreenSaver:sender
- {
- [self screenSaverMode];
- NXSetAutoDimState(evs, YES);
- [self doScreenSaver:self];
- NXSetAutoDimState(evs, NO);
- [self normalMode]; //usually not necessary
-
- // reset to fire again
- [self calcDimTime];
-
- return self;
- }
-
-
- - doScreenSaver:sender
- {
- BOOL autoDimmed;
- int oldWindowType;
- BOOL mouseOK, oldTimerValid;
- BOOL ignoreMouseMovement = NO;
- BOOL isHidden;
- NXRect trackingRect;
- NXPoint mouseLoc;
- BOOL passwordOK;
- BOOL stoleActivation = NO;
- int oldActiveApp = 0;
- int iterationCount = 0;
-
- // must be sure we don't enter on timed entry after faking saver
- doingSaver = YES;
-
- isHidden = [NXApp isHidden];
- if (isHidden)
- {
- [NXApp unhideWithoutActivation:self];
- }
-
- // force activation here so we get keystrokes if someone
- // just types his password.
- if ([password isLocked])
- {
- oldActiveApp = [NXApp activateSelf:YES];
- stoleActivation = YES;
- }
-
- [self setVirtualViewIndexAndIncrement:YES];
-
- //save old window state
- oldWindowType = [windMatrix selectedRow];
-
- globalTier = SAVERTIER;
-
- [self blackOutAllScreens];
-
- //background window on screen
- [windMatrix selectCellAt:BACKWINDOW :0];
- [self changeWindowTypeAndRemember:NO];
-
- //nuke timer so timed entry doesn't fire
- oldTimerValid = timerValid;
- [self removeTimer];
-
-
- //set background window tier to SAVERTIER
- if ([self backingTypeForView:spaceView] == NX_BUFFERED)
- {
- // make sure the one shot buffer really exists
- //[spaceWindow display]; //xxx
- if ([spaceWindow windowNum] <= 0) [spaceWindow display];
- PSsetwindowlevel(SAVERTIER, [spaceWindow windowNum]);
- }
- else
- {
- PSsetwindowlevel(SAVERTIER, [spaceWindow windowNum]);
- [spaceView fillBoundsWithBlack];
- [spaceView display];
- }
-
- NXPing();
- [self screenSaverMode];
-
- PSsetwaitcursorenabled(NO);
-
- if ([spaceView respondsTo:@selector(enteredScreenSaverMode)])
- [spaceView enteredScreenSaverMode];
-
- do {
- //obscure cursor
- PSobscurecursor();
-
- [spaceView lockFocus];
- if ([spaceView respondsTo:@selector(didLockFocus)])
- [spaceView didLockFocus];
-
-
- if ([spaceView respondsTo:@selector(ignoreMouseMovement)])
- ignoreMouseMovement = [spaceView ignoreMouseMovement];
-
- [spaceWindow getMouseLocation:&mouseLoc];
- trackingRect.origin.x = mouseLoc.x - 100;
- trackingRect.origin.y = mouseLoc.y - 100;
- trackingRect.size.width = trackingRect.size.height = 200;
-
- do {
- if ((++iterationCount & 0x7f)==0) PSobscurecursor();
-
- [spaceView oneStep];
- [spaceWindow flushWindow];
- NXPing(); // Synchronize postscript for smoother animation
-
- // note: window and view coordinates the same!
- // so I don't have to convert to view coord system
- if (ignoreMouseMovement) mouseOK = YES;
- else
- {
- [spaceWindow getMouseLocation:&mouseLoc];
- mouseOK = [spaceView mouse:&mouseLoc inRect:&trackingRect];
- }
-
- [spaceView oneStep];
- [spaceWindow flushWindow];
- NXPing(); // Synchronize postscript for smoother animation
-
- autoDimmed = NXAutoDimState(evs);
- } while (autoDimmed && mouseOK);
-
- [spaceView unlockFocus];
-
- // force activation here in case anyone changed it out
- // from under me. (workspace does this, dog gone it!)
- if ([password isLocked])
- {
- [NXApp activateSelf:YES];
- }
-
- passwordOK = [password checkPassword:
- NXLocalString("Screen is locked. Enter password to unlock:",0,0)
- randomPos:YES checkLock:YES withView:spaceView];
-
- if (!passwordOK) NXSetAutoDimState(evs, YES);
-
- } while (!passwordOK);
-
- if ([spaceView respondsTo:@selector(willExitScreenSaverMode)])
- [spaceView willExitScreenSaverMode];
-
- NXSetAutoDimState(evs, NO);
-
- PSsetwaitcursorenabled(YES);
-
- [self normalMode];
-
- //background window tier to BACKGROUNDTIER
- PSsetwindowlevel(BACKGROUNDTIER, [spaceWindow windowNum]);
- globalTier = BACKGROUNDTIER;
-
- if (([self backingTypeForView:spaceView] != NX_BUFFERED) &&
- oldWindowType == BACKWINDOW)
- // this justs fixes a display bug for really lazy nonretained windows
- {
- [spaceView fillBoundsWithBlack];
- [spaceView display];
- }
-
- if (oldTimerValid) [self createTimer];
-
- [self unBlackOutAllScreens];
-
- //restore old window state
- [windMatrix selectCellAt:oldWindowType :0];
- [self changeWindowTypeAndRemember:NO];
-
- if (stoleActivation)
- {
- if (oldActiveApp) [NXApp activate:oldActiveApp];
- else [NXApp deactivateSelf];
- }
-
- if (isHidden)
- {
- [NXApp hide:self];
- }
-
- doingSaver = NO;
-
- return self;
- }
-
- - appWillTerminate:sender
- {
- [self normalMode];
- return self;
- }
-
- - appDidBecomeActive:sender
- {
- id theMatrix;
-
- theMatrix = [viewSelectionBrowser matrixInColumn:0];
- [theMatrix scrollCellToVisible:realViewIndex :0];
- return self;
- }
-
- - app:sender powerOffIn:(int)ms andSave:(int)aFlag
- {
- return [NXApp terminate:self];
- }
-
- - getPrioritySetting
- {
- const char *ptr;
- int val;
-
- [mySlider setMinValue: 0];
- [mySlider setMaxValue: 10];
-
- ptr = NXGetDefaultValue([NXApp appName], "priority");
- if (ptr)
- {
- sscanf(ptr,"%d",&val);
- if (val >= 0 && val <= 10) priority = val;
- else priority = 4;
- }
- else priority = 4;
-
- [[mySlider cell] setIntValue:priority];
- [[priorityLevel cell] setIntValue:priority];
-
- // use mach call rather than unix - mach lets me increase priority!
- // setpriority(PRIO_PROCESS, 0, priority);
- cthread_priority(cthread_self(), priority, FALSE);
-
- return self;
- }
-
- - changeSliderValue:sender
- {
- priority = [[mySlider cell] intValue];
- [[priorityLevel cell] setIntValue:priority];
- return self;
- }
-
- - saveSliderValue
- {
- char str[50];
- // setpriority(PRIO_PROCESS, 0, priority);
- cthread_priority(cthread_self(), priority, FALSE);
-
- sprintf(str,"%d", priority);
- NXWriteDefault([NXApp appName], "priority", str);
- return self;
- }
-
- - windowWillResize:sender toSize:(NXSize *)frameSize
- {
- if (frameSize->width < 100) frameSize->width = 100;
- if (frameSize->height < 100) frameSize->height = 100;
- return self;
- }
-
- - windowWillClose:sender
- {
- [windMatrix selectCellAt:NOWINDOW :0];
- [self perform:@selector(changeWindowType:) with:self
- afterDelay:1 cancelPrevious:YES];
- return nil;
- }
-
- BStimeval currentTimeInMs()
- {
- struct timeval curTime;
- gettimeofday (&curTime, NULL);
- return (curTime.tv_sec) * 1000 + curTime.tv_usec / 1000;
- }
-
- //
- // Additional methods to handle a common image object for views.
- // Lennart Lovstrad, Rank Xerox EuroPARC, August 1991.
- //
-
- - setImageFromFile: (const char *) filename
- {
- [image free];
-
- image = [[NXImage alloc] initFromFile: filename];
- if (image == nil)
- {
- NXRunAlertPanel([NXApp appName], NXLocalString("Could not open %s",0,0),
- NULL, NULL, NULL, filename);
- image = nil;
- //return nil; //can't return, image is invalid
- }
-
- return [self commonImageInit];
- }
-
- - setImageFromName: (const char *) name
- {
- [image free];
- image = [[NXImage alloc] initFromSection: name];
-
- return [self commonImageInit];
- }
-
- - commonImageInit
- {
- [imageView setImage: image];
- [imageView display];
-
- if ([spaceView respondsTo:@selector(setImage:)])
- [spaceView setImage: image];
-
- if ([self backingTypeForView:spaceView] != NX_BUFFERED)
- {
- [spaceView fillBoundsWithBlack];
- [spaceView display];
- }
-
- return self;
- }
-
- - getImageFile
- {
- const char *filename;
-
- filename = NXGetDefaultValue([NXApp appName], "imageFile");
- if (filename)
- [self setImageFromFile: filename];
- else [self setImageFromName: "defaultImage"];
-
- return self;
- }
-
- - setImageFileFrom: sender
- {
- id openPanel = [OpenPanel new];
- const char *fileTypes[] = {"tiff", "eps", NULL};
-
- if ([openPanel runModalForTypes: fileTypes])
- {
- [self setImageFromFile: [openPanel filename]];
- NXWriteDefault([NXApp appName], "imageFile", [openPanel filename]);
- }
-
- [spaceView display]; //don't know why this is necessary...
-
- return self;
- }
-
- // This should return a float between 0 and 1
- float frandom()
- {
- float val = (random() & 0x7fffffff);
- val /= 0x7fffffff;
- return val;
- }
-
- float randBetween(float a, float b)
- {
- float val, scale, t;
-
- if (a > b)
- { t = a; a = b; b = t;
- }
-
- scale = (b-a);
- val = scale * frandom();
- return (a + val);
- }
-
- @end
-